package com.zwl.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


/**
 * @author zhangweilin
 * @date 2019/6/8 10:58
 * @Description: 文件工具类
 */
public class FileUtil {

    private final static int BUFFER_SIZE = 4096;
    private static Log LOG = LogFactory.getLog(FileUtil.class);

    private final static FileUtil FILE_UTIL = new FileUtil();

    /**
     * 创建文件夹.
     *
     * @param directoryPath 文件夹路径.
     */
    public static void makeDirectory(String directoryPath) {
        File directory = new File(directoryPath);
        if (!directory.exists()) {
            directory.mkdirs();
        }
    }

    /**
     * 读取二进制文件中的字节.
     *
     * @param filePath 文件路径.
     * @return 字节数组.
     * @throws Exception
     */
    public static byte[] getBytesFromFile(File file) throws Exception {
        if (file != null && file.exists()) {
            FileInputStream in = new FileInputStream(file);
            int fileSize = Integer.valueOf(String.valueOf(file.length()));
            ByteArrayOutputStream bout = new ByteArrayOutputStream(fileSize);
            copy(in, bout);
            return bout.toByteArray();
        } else {
            LOG.info(file + " does not exist");
            return null;
        }
    }

    /**
     * 读取二进制文件中的字节.
     *
     * @param filePath 文件路径.
     * @return 字节数组.
     * @throws Exception
     */
    public static byte[] getBytesFromFilePath(String filePath) throws Exception {
        if (filePath != null && !"".equals(filePath)) {
            File file = new File(filePath);
            return getBytesFromFile(file);
        } else {
            return null;
        }
    }

    /**
     * 生成二进制文件.
     *
     * @param bytes    字节数组.
     * @param filePath 生成文件的路径.
     * @throws Exception
     */
    public static File writeBytesToFile(byte[] bytes, String filePath) throws Exception {
        if (filePath != null && !"".equals(filePath)) {
            File file = new File(filePath);
            if (!file.exists()) {
                FileOutputStream out = new FileOutputStream(file);
                out.write(bytes);
                out.flush();
                out.close();
            }
            return file;
        } else {
            return null;
        }
    }

    public static int copy(InputStream in, OutputStream out) throws IOException {
        try {
            int byteCount = 0;
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
                byteCount += bytesRead;
            }
            out.flush();
            return byteCount;
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
            }
            try {
                out.close();
            } catch (IOException ex) {
            }
        }
    }

    public static void zipFiles(File[] srcfile, String zipFilePath) {
        byte[] buf = new byte[1024];
        try {
            // Create the ZIP file
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilePath));
            // Compress the files
            for (int i = 0; i < srcfile.length; i++) {
                FileInputStream in = new FileInputStream(srcfile[i]);
                // Add ZIP entry to output stream.
                out.putNextEntry(new ZipEntry(srcfile[i].getName()));
                // Transfer bytes from the file to the ZIP file
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                // Complete the entry
                out.closeEntry();
                in.close();
            }
            // Complete the ZIP file
            out.close();
        } catch (IOException e) {
            LOG.error(e);
        }
    }

    // 复制文件
    public static void copyFile(File sourceFile, File targetFile) throws IOException {
        BufferedInputStream inBuff = null;
        BufferedOutputStream outBuff = null;
        try {
            // 新建文件输入流并对它进行缓冲
            inBuff = new BufferedInputStream(new FileInputStream(sourceFile));

            // 新建文件输出流并对它进行缓冲
            outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));

            // 缓冲数组
            byte[] b = new byte[1024 * 5];
            int len;
            while ((len = inBuff.read(b)) != -1) {
                outBuff.write(b, 0, len);
            }
            // 刷新此缓冲的输出流
            outBuff.flush();
        } finally {
            // 关闭流
            if (inBuff != null) {
                inBuff.close();
            }
            if (outBuff != null) {
                outBuff.close();
            }
        }
    }

    /**
     * 解压缩文件.
     *
     * @param filePath gz文件路径.
     */
    public static void gunzipFile(String filePath) throws Exception {
        File file = new File(filePath);
        if (file.exists()) {
            String os = System.getProperty("os.name");
            if (os.toLowerCase().startsWith("win")) {
                LOG.info(os + " can't gunzip " + filePath);
            } else {
                Runtime.getRuntime().exec("gunzip " + filePath);
            }
        } else {
            LOG.info(filePath + " does not exist");
        }
    }

    public static void writeFile(String fileName, String filePath, String content) {
        try {
            // 判断文件是否存在，不存在创建
            File f = new File(filePath + fileName);
            if (!f.exists()) {
                File f2 = new File(filePath);
                f2.mkdirs();
                f.createNewFile();
            }
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
            outputStreamWriter.write(content);
            outputStreamWriter.flush();
            outputStreamWriter.close();
        } catch (Exception e) {
            LOG.error(e);
        }

    }

//    /**
//     * 文件删除原来的目录.并创建一个新的目录.
//     *
//     * @param filePath
//     * @throws Exception
//     */
//    public static void deleteDirectory(String filePath) throws Exception {
//        File dirfile = new File(filePath);
//        File[] files = dirfile.listFiles();
//        if (files != null) {
//            for (int i = 0; i < files.length; i++) {
//                // 删除子文件
//                if (files[i].isFile() && files[i].exists()) {
//                    files[i].delete();
//                }
//            }
//        }
//        // 删除子目录
//        if (dirfile.exists() & dirfile.isDirectory()) {
//            FileUtils.deleteDirectory(dirfile);
//        }
//        File f = new File(filePath);
//        f.mkdirs();
//    }

    /**
     * 将正文写入指定文件(.txt,.xml等),如果有存在的目录，先进行目录删除.
     *
     * @param fileaName
     * @param filePath
     * @param content
     */
    public static void writeNewFile(String fileName, String filePath, String content) throws Exception {
        File file = new File(filePath + File.separator + fileName);
        OutputStreamWriter outWrite = null;
        try {
            outWrite = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            outWrite.write(content);
            outWrite.flush();
            outWrite.close();
        } catch (Exception e) {
            throw e;
        } finally {
            if (outWrite != null) {
                outWrite.close();
            }
        }
    }

    /**
     * 文件内容是否为空
     *
     * @param path
     * @return
     */
    public static boolean isExistContentForFile(String path) throws IOException {
        File f = new File(path);
        if (f.exists()) {
            if (f.length() > 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public static void writeFile(OutputStream os, String filePath) {
        try {
            File file = new File(filePath);
            byte[] fileBytes = getBytesFromFile(file);
            os.write(fileBytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.flush();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取文件后缀
     *
     * @param fileName
     * @return
     */
    public static String getSuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 创建多级目录
     */
    public static void createDir(String path) {
        File file = new File(path);
        mkDir(file);


    }

    private static void setPermission(File file) {
        file.setWritable(true, false);
        file.setExecutable(true, false);
        file.setReadable(true, false);
        //设置权限
        Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
        perms.add(PosixFilePermission.OWNER_READ); //设置所有者的读取权限
        perms.add(PosixFilePermission.OWNER_WRITE); //设置所有者的写权限
        perms.add(PosixFilePermission.OWNER_EXECUTE); //设置所有者的执行权限
        perms.add(PosixFilePermission.GROUP_READ); //设置组的读取权限
        perms.add(PosixFilePermission.GROUP_EXECUTE); //设置组的读取权限
        perms.add(PosixFilePermission.GROUP_WRITE); //设置组的写权限
        perms.add(PosixFilePermission.OTHERS_READ); //设置其他的读取权限
        perms.add(PosixFilePermission.OTHERS_EXECUTE); //设置其他的读取权限
        perms.add(PosixFilePermission.OTHERS_WRITE); //设置其他的写权限
        try {
            //设置文件和文件夹的权限
            Path pathParent = Paths.get(file.getParentFile().getAbsolutePath());
            Path pathDest = Paths.get(file.getAbsolutePath());
            Files.setPosixFilePermissions(pathParent, perms);   //修改文件夹路径的权限
            Files.setPosixFilePermissions(pathDest, perms);  //修改图片文件的权限
        } catch (Exception e) {
            LOG.warn(e);
//            e.printStackTrace();
        }
    }

    public static void mkDir(File file) {
        if (file!=null&&file.getParentFile()!=null&&file.getParentFile().exists()) {
            file.mkdir();
            setPermission(file);
        } else {
            mkDir(file.getParentFile());
            file.mkdir();
            setPermission(file);
        }
    }

    /**
     * 获取指定文件夹下所有文件名
     *
     * @param dirFile
     * @return
     * @throws Exception
     */
    public static ArrayList<String> getAllFilePath(File dirFile) {
        ArrayList<String> allFilePathList = new ArrayList<>();
        if (dirFile.exists()) {
            File files[] = dirFile.listFiles();
            for (File file : files) {
                // 如果遇到文件夹则递归调用。
                if (file.isDirectory()) {
                    // 递归调用
                    ArrayList<String> allSubFilePathList = getAllFilePath(file);
                    allFilePathList.addAll(allSubFilePathList);
                } else {
                    // 如果遇到文件夹则放入数组
                    if (dirFile.getPath().endsWith(File.separator)) {
                        allFilePathList.add(dirFile.getPath() + file.getName());
                    } else {
                        allFilePathList.add(dirFile.getPath() + File.separator
                                + file.getName());
                    }
                }
            }
        }
        return allFilePathList;
    }

    /**
     * 获取指定文件夹下所有文件名
     *
     * @param dirFile
     * @return
     * @throws Exception
     */
    public static List<String> getDirPath(File dirFile,String fileOrDirNameFiler) {
        List<String> dirPathList = new ArrayList<>();
        if (dirFile.exists()) {
            File fileArr[] = dirFile.listFiles();
            for (File file : fileArr) {
                // 如果遇到文件夹则递归调用。
                if (file.isDirectory()) {
					String path = file.getPath();
					if (path.endsWith(fileOrDirNameFiler)) {
						dirPathList.add(path);
					}
					// 递归调用
					List<String> subDirPathList = getDirPath(file, fileOrDirNameFiler);
					dirPathList.addAll(subDirPathList);
                }
            }
        }
        return dirPathList;
    }


    /**
     * 获取指定文件夹下所有文件名
     *
     * @param dirFile
     * @return
     * @throws Exception
     */
    public static ArrayList<File> getAllFile(File dirFile) {
        ArrayList<File> allFileList = new ArrayList<>();
        if (dirFile.exists()) {
            File files[] = dirFile.listFiles();
            for (File file : files) {
                // 如果遇到文件夹则递归调用。
                if (file.isDirectory()) {
                    // 递归调用
                    ArrayList<File> subAllFileList = getAllFile(file);
                    allFileList.addAll(subAllFileList);
                } else {
                    allFileList.add(file);
                }
            }
        }
        return allFileList;
    }

    /**
     * 从jar包中获取指定文件的输入流
     *
     * @param fileName
     * @return
     */
    public static InputStream getInputStreamFromJarFile(String fileName) {
//        InputStream inputStream = FileUtil.class.getClassLoader().getResourceAsStream(fileName);
        InputStream inputStream = FILE_UTIL.getClass().getResourceAsStream(fileName);
        return inputStream;
    }

    public static InputStream getInputStreamFromFilePath(String filePath) throws FileNotFoundException {
        return new FileInputStream(filePath);

    }

    public static InputStream getInputStreamFromFile(File file) throws FileNotFoundException {
        return new FileInputStream(file);

    }

    /**
     * 从jar包读取资源文件
     *
     * @param fileName
     * @param isFilter 是否过滤注释等
     * @return
     */
    public static String readFromJarFile(String fileName, boolean isFilter) {
        InputStream inputStream = getInputStreamFromJarFile(fileName);
        System.out.println("inputStream = " + inputStream);
        return readFromInputStream(inputStream, isFilter);
    }

    /**
     * 从jar包读取资源文件
     *
     * @param fileName
     * @param isFilter 是否过滤注释等
     * @return
     */
    public static String readFromFile(String fileName, boolean isFilter) throws FileNotFoundException {
        InputStream inputStream = getInputStreamFromFilePath(fileName);
        return readFromInputStream(inputStream, isFilter);
    }

    /**
     * 从输入流读取文本内容
     *
     * @param inputStream
     * @param isFilter
     * @return
     */
    public static String readFromInputStream(InputStream inputStream, boolean isFilter) {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        try {
            while ((length = inputStream.read(buffer)) != -1) {
                result.write(buffer, 0, length);
            }
            String str = result.toString("UTF-8");
            if (isFilter) {
                str = str.replaceAll("/\\*[\\s\\S]*?\\*/", "");
            }
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取文件扩展名*
     *
     * @param fileName 文件名
     * @return 扩展名
     */
    public static String getExtension(String fileName) {
        int i = fileName.lastIndexOf(".");
        if (i < 0) {
            return null;
        }

        return fileName.substring(i + 1);
    }

    /**
     * 获取文件扩展名*
     *
     * @param file 文件对象
     * @return 扩展名
     */
    public static String getExtension(File file) {
        if (file == null) {
            return null;
        }

        if (file.isDirectory()) {
            return null;
        }

        String fileName = file.getName();
        return getExtension(fileName);
    }

    /**
     * 读取文件*
     *
     * @param filePath 文件路径
     * @return 文件对象
     */
    public static File readFile(String filePath) {
        File file = new File(filePath);
        if (file.isDirectory()) {
            return null;
        }

        if (!file.exists()) {
            return null;
        }

        return file;
    }

    /**
     * 复制文件
     *
     * @param oldFilePath 源文件路径
     * @param newFilePath 目标文件毒经
     * @return 是否成功
     */
    public static boolean copyFile(String oldFilePath, String newFilePath) {
        try {
            int byteRead = 0;
            File oldFile = new File(oldFilePath);
            if (oldFile.exists()) { // 文件存在时
                InputStream inStream = new FileInputStream(oldFilePath); // 读入原文件
                FileOutputStream fs = new FileOutputStream(newFilePath);
                byte[] buffer = new byte[1444];
                while ((byteRead = inStream.read(buffer)) != -1) {
                    fs.write(buffer, 0, byteRead);
                }
                inStream.close();
                fs.close();
                return true;
            }
            return false;
        } catch (Exception e) {
            System.out.println("复制单个文件操作出错 ");
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除文件
     *
     * @param filePath 文件地址
     * @return 是否成功
     */
    public static boolean delFile(String filePath) {
        return delFile(new File(filePath));
    }

    /**
     * 删除文件
     *
     * @param file 文件对象
     * @return 是否成功
     */
    public static boolean delFile(File file) {
        if (file.exists()) {
            return file.delete();
        }
        return false;
    }

    /**
     * png图片转jpg*
     *
     * @param pngImage png图片对象
     * @param jpegFile jpg图片对象
     * @return 转换是否成功
     */
    public static boolean png2jpeg(File pngImage, File jpegFile) {
        BufferedImage bufferedImage;

        try {
            bufferedImage = ImageIO.read(pngImage);

            BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);

            ImageIO.write(bufferedImage, "jpg", jpegFile);

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断文件是否是图片*
     *
     * @param imgFile 文件对象
     * @return
     */
    public static boolean isImage(File imgFile) {
        try {
            BufferedImage image = ImageIO.read(imgFile);
            return image != null;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 根据系统当前时间，返回时间层次的文件夹结果，如：upload/2015/01/18/0.jpg
     *
     * @return
     */
    public static String getTimeFilePath() {
        return new SimpleDateFormat("/yyyy/MM/dd").format(new Date()) + "/";
    }

    /**
     * 将文件头转换成16进制字符串
     *
     * @param src 原生byte
     * @return 16进制字符串
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 得到文件头
     *
     * @param file 文件
     * @return 文件头
     * @throws IOException
     */
    public static String getFileContent(File file) throws IOException {
        byte[] b = new byte[28];
        InputStream inputStream = null;

        try {
            inputStream = new FileInputStream(file);
            inputStream.read(b, 0, 28);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        }
        return bytesToHexString(b);
    }


    public ByteArrayOutputStream parse(InputStream in) throws Exception {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        int ch;
        while ((ch = in.read()) != -1) {
            swapStream.write(ch);
        }
        return swapStream;
    }

    public ByteArrayInputStream parse(OutputStream out) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos = (ByteArrayOutputStream) out;
        ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream;
    }



	public static File getParentFile(File file1,int level) {
		for (int i = 0; i < level && file1 != null; i++) {
			if (file1.exists()) {
				file1 = file1.getParentFile();
			}else{
				return file1;
			}
		}
		return file1;
	}

}
